home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Precision Software Appli…tions Silver Collection 4
/
Precision Software Applications Silver Collection Volume 4 (1993).iso
/
stats
/
chadyn.exe
/
YLYAP.C
< prev
next >
Wrap
C/C++ Source or Header
|
1988-11-28
|
22KB
|
744 lines
/******* YLYAP.C for computing Lyapunov numbers and NEWTON's Method *******/
/*********************** (C) 1986,7,8 by JAMES A. YORKE **********************/
#define EL if(printer >=1) erase_line()
/*********** Routines in YLYAP *************
lyapinit() this should be done when dot = -preiter but isn't
lyapunov() one step in computing lyap numbers corresponding to one
step of the differential equation;
this is called by iterate_map()
print_lyap(output)
set_y() y[j] is set for j = 5,...,20 -- for dif eq 223
set_vector()
orthonormalize() orthonormalize the vectors
orthogonalize(i) change vector[][i] into vector[][i] so that vector[][i]
is perpendicular to previous ones. This new vector[][i] is
unnormallized
double dot_p(kk,ii) returns dot product
Newton Routines
newtinit()
newton(N)
************************************************************/
/* vec_dim is the number of coordinates of the Lyapunov vectors
so jj satisfies 0 <= jj < vec_dim */
/* num_lyap is the number of Lyapunov exponents to be computed.
The default value is 0 and the max is vec_dim
so i satisfies 0 <= i < num_lyap */
/* lyapzero : y[lyapzero] is the zeroth coord of the zeroth Lyapunov
vector */
/* these three are all set by select_map() in YMAPS.C.
In addition that routine sets init_process() to be something like
jac_223() to set appropriate
constant jacobian terms in Ydes */
#include "yinclud.h"
static double vector[5][5],
dot_prod[5];
static double product; /* this is for computing products of norms of
the vector[][] vectors */
/* in 223, y[0] is time,y[1] and y[3] are x variables
and y[2] and y[4] are x-primes */
lyapinit() { /* this should be done when dot = -preiter and
when num_lyap is changed especially if it is
done while the program is iterating */
int i;
int coord;
lyaptime = 0;
if(step != -9999) {
lyapstep = step * its_per_plot;/* dif equation case */
dim = lyapzero + num_lyap * vec_dim;/* for rungekutta */
}
else
lyapstep = its_per_plot;/* map case */
for(i = 0; i < num_lyap; i++)
for(coord = 0; coord < vec_dim; coord++)
y[lyapzero + coord + vec_dim * i] = 1.+ coord + vec_dim * i;
set_vector();
orthonormalize();
set_y();
for(i = 0; i < vec_dim; i++)/* initialize vector lyapsum */
lyapsum[i] = 0;
if(level >= PROCESS && printer > 0) {
scr_rowcol(1, 0);
PRINT "\nLyapunov exponents are now(re-)initialized.");
}
}
lyapunov() { /* This routine takes the Lyapunov vectors and
orthonormalizes them; in the process, it
computes growth and shrinkage rates;
sometimes it prints out estimates of
exponents; one step in computing lyap
numbers corresponding to one step of the
differential equation; it is called by
processi() in Q.C */
FILE * output;
int puts();
output = StOutPut; /* this step of introducing output rather than
using StOutPut directly seems stupid but
print_lyap(stdout) doesn't seem to work with
the big model DeSmet */
if(dot == 0) {
lyapinit(); /* this should really be done at the outset of
computation */
}
else {
set_vector();
orthonormalize();
set_y();
if(printer > 2) {
scr_rowcol(0, 0);
print_lyap(output);
if((10 * (dot / 10)) == dot) {
/* print warning evey tenth dot */
erase_line();
PRINT
"Hit 2 to stop printing & speed computing lots\n");
}
}
}
}
print_lyap(output)
FILE * output;
{
int num = num_lyap;
int i;
if(num_lyap < storeNumLyap)
num = storeNumLyap;/* needed for straddle orbits */
if(lyaptime > 0) {
if(level >= PROCESS) {
fprintf(output, "\n");
EL;
fprintf(output, "\n");
EL;
fprintf(output, "dot =%ld; ", dot);
/* no '\n' wanted */
}
EL;
fprintf(output, "Lyap exps= ");
for(i = 0; i < num; i++)
fprintf(output, "%lf ", lyapsum[i] / lyaptime);
lyap_dim(output);
}
else
if(lyaptime < 0)
fprintf(output,
"No lyap exponent totals computed yet; lyaptime = 0 \r");
else
if(lyaptime == 0 && level >= PROCESS
&& output == StOutPut)
/* for clearing out old print on screen */
erase_line();
}
lyap_dim(output)
FILE * output;
{
int i;
double SumOfExponents = 0.0;
double LyapDimen;
for(i = 0; (SumOfExponents += lyapsum[i]) >= 0.0
&& i < num_lyap; i++);/* sets i */
if(SumOfExponents < 0) {/* the sum of i exponents is >= 0 *//* notice
lyapsum[i] must be negative */
SumOfExponents = SumOfExponents - lyapsum[i];
LyapDimen = i + SumOfExponents / (-lyapsum[i]);
fprintf(output, "Lyapunov Dimension = %lf. ", LyapDimen);
}
else {
if(num_lyap == vec_dim)
fprintf(output, "Lyapunov dimension = %d ", vec_dim);
}
} /* see also yintrpt for printout */
set_y() { /* y[j] is set for j = 5,...,20 -- for dif eq
223 */
int i, coord;
for(i = 0; i < num_lyap; i++)
for(coord = 0; coord < vec_dim; coord++)
y[lyapzero + coord + vec_dim * i] = vector[coord][i];
}
set_vector() {
int i, coord;
for(i = 0; i < num_lyap; i++)
for(coord = 0; coord < vec_dim; coord++)
vector[coord][i] = y[lyapzero + coord + vec_dim * i];
}
orthonormalize() { /* orthonormalize the vectors */
double norm;
int coord;
int i;
product = 1.;
for(i = 0; i < num_lyap; i++) {
if(i > 0)
orthogonalize(i);
/* make ith vector perpendicular to the earlier
vectors */
norm = 0;
for(coord = 0; coord < vec_dim; coord++)
norm += vector[coord][i] * vector[coord][i];
norm = sqrt(norm);
product *= norm;
for(coord = 0; coord < vec_dim; coord++)
vector[coord][i] = vector[coord][i] / norm;
if(dot > 0)
lyapsum[i] = lyapsum[i] + log(norm);
} /* ith vector is finished */
if(dot > 0)
lyaptime = lyaptime + lyapstep;
return;
}
/* ORTHOGONALIZE - change vector[][i] into vector[][i] so that
* vector[][i] is perpendicular to previous
* ones. This new vector[][i] is unnormalized.
*/
orthogonalize(i)
int i;
{
int k, coord;
double dot_p();
/* dot_prod[k] will be the dot product of the k th vector with the ith already
normalized vector */
for(k = 0; k < i; k++) {
dot_prod[k] = dot_p(i, k);
for(coord = 0; coord < vec_dim; coord++)
vector[coord][i] = vector[coord][i] - vector[coord][k] * dot_prod[k];
} /* now we have orthogonal but unnormalized
vector # i */
}
double dot_p(kk, ii) /* returns dot product as function value */
int ii,
kk;
{
int crd;
double dotprd = 0.0;
for(crd = 0; crd < vec_dim; crd++)
dotprd += vector[crd][ii] * vector[crd][kk];
return(dotprd);
}
/* Newton Routines */
newtinit() {
int coord;
dim = lyapzero + vec_dim * vec_dim;/* necessary for rungekutta */
for(coord = 0; coord < vec_dim * vec_dim; coord++)/* matrix = 0 */
y[lyapzero + coord] = 0.;
for(coord = 0; coord < vec_dim; coord++)/* diagonal elements = 1 */
y[lyapzero + coord + vec_dim * coord] = 1.;
}
#define IF1PRINT if( printer >=1 ) PRINT
double newton(N, quasi) /* quasi = 1 means use Quasi-Newton; y1[] is
used as the initial state; error is returned
*/
int N,
quasi; /* N is the number of iterates */
{
int J;
double old[VECDIM],
new[VECDIM],
dif[VECDIM],
miss,
miss2,
factor;
double ystep[VECDIM];
double yy[EQUATIONS];
int i,
n_lyap;
erase_line();
ResetScrnLineAtTop();
InNewton = 1; /* indicates we are in newton(); this causes
suppression of lyapunov() in iterate_map()
*/
setequal(0, 1, eqn1); /* set y to equal the initialization vector */
store(yy, y, zeroth); /* stores y in yy -- yy is not currently in
use anywhere */
n_lyap = num_lyap; /* save num_lyap so it can be reset */
num_lyap = vec_dim; /* map iterates look at this number */
newtinit();
for(i = 0; i < vec_dim; i++)
old[i] = y[zeroth + i];
/* *** now iterate and report resulting error *** */
for(i = 0; i < N; i++)
(*iteratee) ();
for(i = 0; i < vec_dim; i++)
dif[i] = old[i] - y[zeroth + i];
/* for 2 dimensional, the two dimensions are
zeroth and zeroth+1 */
miss = 0;
for(i = 0; i < vec_dim; i++)
miss += dif[i] * dif[i];
miss = sqrt(miss);
EL;
IF1PRINT "PERIOD OF ORBIT(set by \"NP\") is %d \n", period);
EL;
IF1PRINT
"Before Newton step, a periodic orbit is missed by %le \n"
,miss);
/***********************************************************
lyapzero is probably 2 so the jacobian matrix is
( y[2+0] y[2+2] )
( y[2+1] y[2+3] )
then the inverse of DF-Id is
( y[2+3]-1 -y[2+2] )
( -y[2+1] y[2+0]-1 ) divided by its determinant
************************************************************/
/******** now compute and report recommended newton step(ystep) ************/
if(vec_dim == 2 && printer > 0)
newt2 (ystep, N, dif);
else
newtMany(ystep, dif);
EL;
IF1PRINT
"Newton step has norm %le \n"
,sqrt(ystep[0] * ystep[0] + ystep[1] * ystep[1]));
factor = 1.;
/************* Now check to see if we get an improvement in error ************/
num_lyap = 0; /* this is so the next iterate does not change
the tangent vectors; hence when y[] is
displayed using 300, it will display matrix
elements */
dim = lyapzero; /* rungekutta uses dim */
setequal(0, 1, zeroth);/* set y to equal the initialization vector;
for maps this line can be deleted but for
dif eqns it resets time */
for(i = 0; i < vec_dim; i++)
y[zeroth + i] = old[i] + ystep[i] * factor;
for(i = 0; i < vec_dim; i++)
new[i] = y[zeroth + i];
setequal(1, 0, zeroth);
for(i = 0; i < N; i++)
(*iteratee) ();
for(i = 0; i < vec_dim; i++)
dif[i] = new[i] - y[zeroth + i];
miss2 = 0;
for(i = 0; i < vec_dim; i++)
miss2 += dif[i] * dif[i];
miss2 = sqrt(miss2);
EL;
PRINT
"AFTER Newton step, a periodic orbit is missed by %le \n"
,miss2);
EL;
IF1PRINT "\n");
/**** now set y and y1 to equal the result of one Newton step ****/
setequal(0, 1, zeroth);/* reset y to equal the old vector; affects dif
eqns that have time as a variable */
/************************** QUASI-NEWTON ***************************/
/**if the error after the Newton step is too big, cut the size ******/
for(J = 0; (quasi == 1) && (miss2 > miss) && (miss2 >.000001) && (J < 10);
J++) {
factor *= 0.5;
setequal(0, 1, zeroth);/* reset y to equal the old vector */
for(i = 0; i < vec_dim; i++)
y[zeroth + i] = old[i] + ystep[i] * factor;
for(i = 0; i < vec_dim; i++)
new[i] = y[zeroth + i];
for(i = 0; i < N; i++)
(*iteratee) ();
for(i = 0; i < vec_dim; i++)
dif[i] = new[i] - y[zeroth + i];
miss2 = 0;
for(i = 0; i < vec_dim; i++)
miss2 += dif[i] * dif[i];
miss2 = sqrt(miss2);
EL;
PRINT
"Using Newton step TIMES%le, a periodic orbit is missed by %le\n"
,factor, miss2);
}
setequal(0, 1, zeroth);/* reset y to equal the old vector plus the
step times factor */
for(i = 0; i < vec_dim; i++)
y[zeroth + i] = old[i] + ystep[i] * factor;
num_lyap = n_lyap;
dim = lyapzero + vec_dim * num_lyap;
/* this is needed for "300" for printing out
the right number of coordinates of y[] and
for the differential equation solver */
EL;
IF1PRINT "\n");
EL;
IF1PRINT "\n");
setequal(1, 0, eqn1); /* set the initialization vector equal to y */
InNewton = 0; /* indicates newton() is being left */
return(miss2);
}
newtMany(ystep, dif) /* mat = df - id, mat*ystep = dif = old -
(y+zeroth) */
double *ystep,
*dif;
{
int i,
j;
double mat[MATDIM];
for(i = 0; i < vec_dim; i++)/* for gauss() */
for(j = 0; j < vec_dim; j++)
mat[i + j * vec_dim] = y[lyapzero + i * vec_dim + j];
for(i = 0; i < vec_dim; i++)/* subtract identity */
mat[i + i * vec_dim] -= 1.0;
gauss(mat, ystep, dif, vec_dim);
/* solve mat x = b where vec_dim is the
dimension of the vectors and if for vec_dim
= 2, mat = ( mat[0] mat[1] ) ( mat[2] mat[3]
) WARNING: mat is altered though b is not */
for(i = 0; i < vec_dim; i++)/* for gauss() */
EL;
IF1PRINT
"after;[%d]:ystep=%lf dif=%lf\n", i, ystep[i], dif[i]);
return;
}
newt2 (ystep, N, dif) /* computes ystep[] in two dimensions and
prints out eigenvalues,etc */
double *ystep,
*dif;
int N;
{
double A,
B,
C,
D,
det;
double a,
b,
c,
d;
a = y[lyapzero];
b = y[lyapzero + 2];
c = y[lyapzero + 1];
d = y[lyapzero + 3];
EL;
IF1PRINT
"The Jacobian Matrix for %d iterate(s) is\n", N);
EL;
IF1PRINT
" ( %lf, %lf )\n", a, b);
EL;
IF1PRINT
" ( %lf, %lf ) Jacobian det = %lf\n", c, d, a * d - b * c);
radical = (a + d) * (a + d) - 4 * (a * d - b * c);
EL;
if(radical > 0) { /* distinct real eigenvalues */
EigenValue1 = (a + d - sqrt(radical)) / 2;
EigenValue2 = (a + d + sqrt(radical)) / 2;
EL;
IF1PRINT
"The eigenvalues are %lf and %lf \n"
,EigenValue1, EigenValue2);
if(b != 0) {
Ycomponent1 = -(a - EigenValue1) / b;
Ycomponent2 = -(a - EigenValue2) / b;
EL;
IF1PRINT
" with eigenvectors: (1, %lf) (1, %lf) \n",
Ycomponent1, Ycomponent2);
}
}
if(b == 0 && c != 0) {
EL;
IF1PRINT
"with eigenvectors: (%lf, 1) (%lf, 1)\n",
-(d - EigenValue1) / c, -(d - EigenValue2) / c);
}
if(radical < 0) { /* complex eigenvalues */
EL;
IF1PRINT
"The eigenvalues are complex and = %lf +- i%lf \n"
,(a + d) / 2, sqrt(-radical) / 2);
}
A = y[lyapzero + 3] - 1;
B = -y[lyapzero + 2];
C = -y[lyapzero + 1];
D = y[lyapzero] - 1;
det = A * D - B * C;
if(det <.00000000001 && det > -.00000000001) {
EL;
IF1PRINT
"+1 is an eigenvalue; cannot take Newton step\n");
InNewton = 0;
return;
}
EL;
IF1PRINT
"The Newton Matrix, i.e. the inverse of Jacobian-Id, is \n");
A = A / det;
B = B / det;
C = C / det;
D = D / det;
EL;
IF1PRINT
" ( %lf, %lf )\n", A, B);
EL;
IF1PRINT
" ( %lf, %lf ) with determinant %lf\n", C, D, 1 / det);
/* (A,B,C,D) = inverse of [Jacobian - Identity] */
/* y = old + (A,B,C,D)*(old - y) */
ystep[0] = A * dif[0] + B * dif[1];
ystep[1] = C * dif[0] + D * dif[1];
return;
}
/* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* */
/* Routine gauss() is to use gaussian method to solve system */
/* of linear equations. It contains three subroutines which are*/
/* pivot(),tri() and solve(). Pivot() is used to pivot each */
/* coming column, tri() is to be used to transform the matrix */
/* into upper triangular matrix, and solve() is to use chasing */
/* method to solve the linear system with an upper triangular */
/* matrix on the left hand side. */
/* */
/* Notice: We input all the matries as vectors, i.e. an N by N */
/* matrix is to be considered as a vector with dimension N*N, */
/* and we order them row by row. Therefore the element a[i][j] */
/* of an ordinary matrix is denoted as a[i*vec_dim+j] here. */
/* */
/* */
/* To use this subroutine you should first define */
/* VECDIM & MATDIM, where VECDIM = dimension of the vector */
/* (the number of variables) and MATDIM = the dimension of the */
/* matrix, i.e. MATDIM=VECDIM*VECDIM. The format of define is */
/* #define VECDIM 3 . Then you should give */
/* values to the a[i]'s. Now you simply call routine gauss() */
/* to solve your linear equation. Here is an example: */
/* */
/* #include <stdio.h> */
/* */
/* #define VECDIM 4 */
/* #define MATDIM 16 */
/* */
/* solve ax = b */
/* main() */
/* { */
/* double a[MATDIM],b[VECDIM],x[VECDIM]; */
/* */
/* a[0]=2; */
/* a[1]=0; */
/* a[2]=1; */
/* a[3]=1; */
/* b[0]=0; */
/* b[1]=1; */
/* */
/* gauss(a,x,b); */
/* printf("%lf,%lf\n",x[0],x[1]); */
/* } */
/* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* */
gauss(a, x, b, vec_dim) /* solve ax = b where vec_dim is the dimension
of x and b and where for vec_dim = 2, a = (
a[0] a[1] ) ( a[2] a[3] ) WARNING: a is
altered though b is not */
double *a,
*x,
*b;
int vec_dim;
{
int j;
for(j = 0; j < vec_dim; j++) {
x[j] = b[j]; /* now b will not be changed */
}
for(j = 0; j < vec_dim; j++) {
pivot(a, x, j, vec_dim);
tri(a, x, j, vec_dim);
}
solve(a, x, vec_dim);
return;
}
/* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* */
/* subroutine pivot() pivots the j-th column of the current matrix*/
/* a[i][j] (with i>=j) so that in tri() we can avoid to devide */
/* something by zero. Furthermore, because of pivoting, we can */
/* (in some extent) minimize the accumutive error due to round */
/* off by computer. */
/* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* */
pivot(a, z, j, vec_dim)
double *a,
*z;
int j,
vec_dim;
{
int i,
l,
k,
jj,
kk;
double s[MATDIM],
x[VECDIM],
b[VECDIM],
d,
aa;
/* s and x are just passing variables. When we switch two */
/* rows, we put the first row into the passing variables and */
/* the put the second row into the first one, and finally we */
/* put the the passing variables' value into the second row. */
for(i = j; i < vec_dim; i++) {
aa = a[i * vec_dim + j];
(aa < 0) ? (b[i] = -aa) : (b[i] = aa);
}
/* b is the absolute value of the coresponding a[i][j] so to */
/* make the following comparison possible.(To find the one */
/* with the largest absolute value in the j-th column). */
k = j;
d = b[j];
for(i = j + 1; i < vec_dim; i++)
if(b[i] > d) {
d = b[i];
k = i;
}
if(d == 0) {
printf("pivot(): The system is unsolvable because the \
matrix is singular!");
exit(1);
}
/* the following is to switch the entries of the rows due to */
/* partial pivoting. */
for(l = j; l < vec_dim; l++) {
jj = j * vec_dim + l;
kk = k * vec_dim + l;
s[jj] = a[jj];
a[jj] = a[kk];
a[kk] = s[jj];
}
x[j] = z[j];
z[j] = z[k];
z[k] = x[j];
return;
}
/* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* */
/* subroutine tri() is to transform the matrix into an upper */
/* triangular one so that it is easy to solve. What we really */
/* do in this subroutine is to transform the j-th column of the*/
/* current matrix into the form such that all elements a[i][j] */
/* with i>j are zero. */
/* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* */
tri(a, x, j, vec_dim)
double *a,
*x;
int j,
vec_dim;
{
int i,
k;
for(i = j + 1; i < vec_dim; i++) {
for(k = j + 1; k < vec_dim; k++)
a[i * vec_dim + k] = a[i * vec_dim + k]
- a[j * vec_dim + k] * (a[i * vec_dim + j] / a[j * vec_dim + j]);
x[i] = x[i] - x[j] * (a[i * vec_dim + j] / a[j * vec_dim + j]);
}
return;
}
/* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* */
/* Subroutine solve() is to use chasing method to solve a system */
/* with an upper triangular matrix on the left hand side. We */
/* solve the n-th unknown first, and put it back in x[n], and */
/* solve n-1th unknown and so on. */
/* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* %* */
solve(a, x, vec_dim)
double *a,
*x;
{
int i,
k;
for(i = vec_dim - 1; i > -1; i--) {
for(k = vec_dim - 1; k > i; k--)
x[i] -= a[i * vec_dim + k] * x[k];
x[i] /= a[i * vec_dim + i];
}
return;
}